package com.xm.bluetoothkotlin.connect

import android.os.Handler
import android.os.HandlerThread
import android.os.Message
import com.blankj.utilcode.util.LogUtils
import com.xm.bluetoothkotlin.connect.back.BleWriteCallback
import com.xm.bluetoothkotlin.constant.DEFAULT_WRITE_DATA_SPLIT_COUNT
import com.xm.bluetoothkotlin.constant.MSG_SPLIT_WRITE_NEXT
import java.util.*
import kotlin.math.roundToInt

/**
 * @创建者:小垚
 * @时间:2021/11/15
 *@描述:
 */
class SplitWriter {

    private var mHandlerThread: HandlerThread? = null
    private var mHandler: Handler? = null

    private var mBleBluetooth: BleBluetooth? = null
    private var mUuid_service: String? = null
    private var mUuid_write: String? = null
    private var mData: ByteArray? = null
    private var mCount = 0
    private var mSendNextWhenLastSuccess = false
    private var mIntervalBetweenTwoPackage: Long = 0
    private var mCallback: BleWriteCallback? = null
    private var mDataQueue: Queue<ByteArray?>? = null
    private var mTotalNum = 0

    fun SplitWriter() {
        mHandlerThread = HandlerThread("splitWriter")
        mHandlerThread!!.start()
        mHandler = object : Handler(mHandlerThread!!.looper) {
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                if (msg.what == MSG_SPLIT_WRITE_NEXT) {
                    write()
                }
            }
        }
    }

    fun splitWrite(
        bleBluetooth: BleBluetooth?,
        uuid_service: String?,
        uuid_write: String?,
        data: ByteArray?,
        sendNextWhenLastSuccess: Boolean,
        intervalBetweenTwoPackage: Long,
        callback: BleWriteCallback?
    ) {
        mBleBluetooth = bleBluetooth
        mUuid_service = uuid_service
        mUuid_write = uuid_write
        mData = data
        mSendNextWhenLastSuccess = sendNextWhenLastSuccess
        mIntervalBetweenTwoPackage = intervalBetweenTwoPackage
        mCount = DEFAULT_WRITE_DATA_SPLIT_COUNT
        mCallback = callback
        splitWrite()
    }

    private fun splitWrite() {
        requireNotNull(mData) { "data is Null!" }
        require(mCount >= 1) { "split count should higher than 0!" }
        mDataQueue = splitByte(mData!!, mCount)
        mTotalNum = mDataQueue!!.size
        write()
    }

    private fun write() {
        if (mDataQueue!!.peek() == null) {
            release()
            return
        }
        val data = mDataQueue!!.poll()
        mBleBluetooth!!.newBleConnector()
            .withUUIDString(mUuid_service!!, mUuid_write!!)
            .writeCharacteristic(
                data,
                object : BleWriteCallback() {
                    override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray) {
                        val position = mTotalNum - mDataQueue!!.size
                        if (mCallback != null) {
                            mCallback!!.onWriteSuccess(position, mTotalNum, justWrite)
                        }
                        if (mSendNextWhenLastSuccess) {
                            val message = mHandler!!.obtainMessage(MSG_SPLIT_WRITE_NEXT)
                            mHandler!!.sendMessageDelayed(message, mIntervalBetweenTwoPackage)
                        }
                    }

                    override fun onWriteFailure(error: String) {
                        if (mCallback != null) {
                            mCallback!!.onWriteFailure(error)
                        }
                        if (mSendNextWhenLastSuccess) {
                            val message = mHandler!!.obtainMessage(MSG_SPLIT_WRITE_NEXT)
                            mHandler!!.sendMessageDelayed(message, mIntervalBetweenTwoPackage)
                        }
                    }
                },
                mUuid_write!!
            )
        if (!mSendNextWhenLastSuccess) {
            val message = mHandler!!.obtainMessage(MSG_SPLIT_WRITE_NEXT)
            mHandler!!.sendMessageDelayed(message, mIntervalBetweenTwoPackage)
        }
    }

    private fun release() {
        mHandlerThread!!.quit()
        mHandler!!.removeCallbacksAndMessages(null)
    }

    private fun splitByte(data: ByteArray, count: Int): Queue<ByteArray?>? {
        if (count > 20) {
            LogUtils.w("Be careful: split count beyond 20! Ensure MTU higher than 23!")
        }
        val byteQueue: Queue<ByteArray?> = LinkedList()
        val pkgCount = if (data.size % count == 0) {
            data.size / count
        } else {
            (data.size / count + 1).toFloat().roundToInt()
        }
        if (pkgCount > 0) {
            for (i in 0 until pkgCount) {
                var dataPkg: ByteArray?
                var j: Int
                if (pkgCount == 1 || i == pkgCount - 1) {
                    j = if (data.size % count == 0) count else data.size % count
                    System.arraycopy(data, i * count, ByteArray(j).also { dataPkg = it }, 0, j)
                } else {
                    System.arraycopy(data, i * count, ByteArray(count).also { dataPkg = it }, 0, count)
                }
                byteQueue.offer(dataPkg)
            }
        }
        return byteQueue
    }

}